#include "stdafx.h"
#include "KnowledgeBase.h"
#include "GlobalData.h"
#include "KeyHandler.h"

BaseCodeAttr::BaseCodeAttr(CONST LPTSTR lpCode,INT freq)
{
	this->frequency = freq;
	_tcscpy(this->baseCode,lpCode);
}
INT BaseCodeAttr::CompareTo(CONST BaseCodeAttr& baseCode) CONST
{
	if(this->frequency > baseCode.frequency)
		return 1;
	else if(this->frequency == baseCode.frequency)
		return _tcscmp(this->baseCode,baseCode.baseCode);
	else
		return - 1;
}
VOID BaseCodeAttr::CopyFrom(CONST BaseCodeAttr& baseCode)
{
	if(this == &baseCode)
		return;
	this->frequency = baseCode.frequency;
	_tcscpy(this->baseCode,baseCode.baseCode);
}
LPTSTR BaseCodeAttr::GetCode()
{
	CONST LPTSTR p = this->baseCode;
	return p;
}
BaseCodeAttr::BaseCodeAttr(CONST BaseCodeAttr& baseCode)
{
	this->CopyFrom(baseCode);
}
BaseCodeAttr& BaseCodeAttr::operator=(CONST BaseCodeAttr& baseCode)
{
	this->CopyFrom(baseCode);
	return *this;
}
BOOL BaseCodeAttr::operator>(CONST BaseCodeAttr& baseCode) CONST
{
	return this->CompareTo(baseCode) > 0;
}
BOOL BaseCodeAttr::operator<(CONST BaseCodeAttr& baseCode) CONST
{
	return this->CompareTo(baseCode) < 0;
}
BOOL BaseCodeAttr::operator==(CONST BaseCodeAttr& baseCode) CONST
{
	return this->CompareTo(baseCode) == 0;
}
BOOL BaseCodeAttr::operator>=(CONST BaseCodeAttr& baseCode) CONST
{
	return !(*this < baseCode);
}
BOOL BaseCodeAttr::operator<=(CONST BaseCodeAttr& baseCode) CONST
{
	return !(*this > baseCode);
}
BOOL BaseCodeAttr::operator!=(CONST BaseCodeAttr& baseCode) CONST
{
	return !(*this == baseCode);
}

VOID KnowledgeProcess::GetBaseCode(CONST std::list<LPBYTE>& byteList,UINT fromPos,std::set<BaseCodeAttr,std::greater<BaseCodeAttr> >& result)
{
	TCHAR preCode[BASE_CODE_LEN] = _T("\0");
	UINT freq = 0;
	BOOL first = TRUE;
	
	for(std::list<LPBYTE>::const_iterator it = byteList.begin();it != byteList.end(); ++it)
	{		
		INT struct_flag = -1000000;
		TCHAR code[BASE_CODE_LEN];
		UINT index = 0;
		BOOL pos = fromPos;
		CONST LPTSTR lpTxt = GetWordCode(*it);
		UINT len = _tcslen(lpTxt);
		if(pos >= len) continue;
		for(;;)
		{
			TCHAR c = *(lpTxt + pos++);
			if(pos == len + 1)
				break;
			if(c == ',')
			{
				if(index == 0)
					continue;
				else
					break;
			}
			code[index++] = c;
			if(index >= BASE_CODE_LEN)
				break;
		}
		if(index != 0)
		{
			code[index] = '\0';
			
			if(first)
			{
				_tcscpy(preCode,code);
				freq = GetFrequency(*it);
				first = FALSE;
				continue;
			}

			if(_tcscmp(code,preCode) == 0)
			{
				INT temp_frq = GetFrequency(*it);
				freq = freq > temp_frq ? freq : temp_frq;
				continue;
			}
			else
			{
				result.insert(BaseCodeAttr(preCode,freq));
				_tcscpy(preCode,code);
				freq = GetFrequency(*it);
				if(1 == index)
				{
					if(!(GlobalData::Setting & STRUCT_CODE_NORMAL))
						freq += struct_flag;
				}
				else
				{
					if(GlobalData::Setting & BASECODE_FREQ_FIRST)
						freq = GlobalData::GetInstance()->GetBaseFreq(code);
				}
			}
		}
	}
	if(freq > 0)
		result.insert(BaseCodeAttr(preCode,freq));
}

VOID KnowledgeProcess::KnowledgeFilter(CONST std::list<LPBYTE>& byteList,CONST std::wstring& comp_str,TCHAR pinYin,std::list<LPBYTE>& result)
{
	BOOL beginFlag = FALSE;
	for(std::list<LPBYTE>::const_iterator it = byteList.begin(); it != byteList.end(); ++it)
	{
		if(pinYin && pinYin != GetPinyin(*it) && GetPinyin(*it) != _T('v'))
			continue;
		if(Str1BeginWithStr2(GetWordCode(*it),comp_str))
		{
			beginFlag = TRUE;
			result.push_back(*it);
		}
		else
		{
			if(beginFlag)
				break;
		}
	}
}

UINT KnowledgeProcess::GetFrequency(CONST LPBYTE lpByte)
{
	return ((LPKNOWLEDGEIMMAP)lpByte)->frequency;
}
TCHAR KnowledgeProcess::GetPinyin(CONST LPBYTE lpByte)
{
	return ((LPKNOWLEDGEIMMAP)lpByte)->pinYin;
}
CONST LPTSTR KnowledgeProcess::GetWord(CONST LPBYTE lpByte)
{
	return ((LPKNOWLEDGEIMMAP)lpByte)->word;
}
CONST LPTSTR KnowledgeProcess::GetWordCode(CONST LPBYTE lpByte)
{
	return (LPTSTR)(lpByte + ((LPKNOWLEDGEIMMAP)lpByte)->dwCodeOffset);
}

BOOL KnowledgeProcess::Str1BeginWithStr2(CONST std::wstring& str1,CONST std::wstring& str2)
{
	UINT str1_index = 0;
	UINT str2_index = 0;
	while(TRUE)
	{
		if(str2.at(str2_index) == _T('\0'))
			return TRUE;
		if(str1.at(str1_index) == _T('\0'))
			return FALSE;
		if (str2.at(str2_index) != str1.at(str1_index))
			return FALSE;
		str1_index += 1;
		str2_index += 1;
	}
	return FALSE;
}

std::list<LPBYTE> KnowledgeProcess::preResult;
UINT KnowledgeProcess::preInputLen = 0;
BOOL KnowledgeProcess::Multiple = FALSE;

KnowledgeProcess::KnowledgeProcess(ImmData* lpImmData)
{
	this->lpCodeList = GlobalData::GetInstance()->GetCodeList();
	this->lpImmData = lpImmData;
}

UINT KnowledgeProcess::TranslateInput()
{	
	Multiple = FALSE;
	TCHAR pinYin = this->lpImmData->GetCompStrClass()->GetPinYin();
	std::wstring comStr = this->lpImmData->GetCompStrClass()->GetCompositionString();
	CONST std::list<LPBYTE>* lptempList = this->lpCodeList;
	if(this->lpImmData->GetCompStrClass()->GetInputLen() > preInputLen && preResult.size())
	{
		lptempList = &preResult;
	}
	std::list<LPBYTE> result;
	KnowledgeFilter(*lptempList,comStr,pinYin,result);
	preResult.clear();

	if(result.size() == 0)
		return 0;
	if(result.size() == 1)
	{
		this->lpImmData->GetCompStrClass()->SetResultString(GetWord(result.front()));
		return 1;
	}
	else
	{
		this->lpImmData->GetCompStrClass()->SetResultString(GetWord(result.front()));
		preInputLen = this->lpImmData->GetCompStrClass()->GetInputLen();
		preResult = result;
	}
	std::set<BaseCodeAttr,std::greater<BaseCodeAttr> > codes;
	GetBaseCode(result,comStr.size(),codes);
	if(codes.size() == 0)
	{
		Multiple = TRUE;
		this->lpImmData->GetCandStrClass()->SetCandidateCount(result.size());
		UINT index = 0;
		for(std::list<LPBYTE>::const_iterator it = result.begin(); it != result.end(); ++it)
		{
			this->lpImmData->GetCandStrClass()->SetCandidateStr(GetWord(*it),index++);			
		}
		return 2;
	}
	else if(codes.size() == 1 && KeyHandler::CurrentKey != VK_BACK)
	{
		this->lpImmData->GetCompStrClass()->PutCode(codes.begin()->GetCode());
		return this->TranslateInput();
	}
	else
	{
		this->lpImmData->GetCandStrClass()->SetCandidateCount(codes.size());
		UINT index = 0;
		for(std::set<BaseCodeAttr,std::greater<BaseCodeAttr> >::iterator it = codes.begin(); it != codes.end(); ++it)
		{
			this->lpImmData->GetCandStrClass()->SetCandidateStr(it->GetCode(),index++);			
		}
		return 2;
	}
	return 2;
}

UINT KnowledgeProcess::SelectTheFirst()
{
	UINT ret = 0;
	do	
	{
		std::wstring code = this->lpImmData->GetCandStrClass()->GetCode(0);
		if(code.size())
		{
			if(KnowledgeProcess::Multiple)
			{
				this->lpImmData->GetCompStrClass()->SetResultString(code);
				return 1;
			}
			else
				this->lpImmData->GetCompStrClass()->PutCode(code);
		}
	}
	while((ret = this->TranslateInput()) == 2);
	return ret;
}